package com.company.nuwa.mybatis.generator.plugins;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.CaseUtils;
import org.mybatis.generator.api.GeneratedJavaFile;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.config.Context;
import org.mybatis.generator.config.PropertyRegistry;
import org.mybatis.generator.internal.util.StringUtility;

import java.text.MessageFormat;
import java.util.Properties;

/**
 * <p>生成额外java文件</p>
 *
 * @author Lionel Lee
 * @version 1.0: ServiceLayerPlugin.java
 * @date 2021/5/4  11:41 星期二
 */
public class ServiceImplPlugin {


    public static GeneratedJavaFile serviceFile(IntrospectedTable introspectedTable,
                                                Context context) {
        Properties contextProperties = context.getProperties();
        String applicationName = contextProperties.getProperty("applicationName");
        String contextPath = contextProperties.getProperty("contextPath");
        String domainObjectName = introspectedTable.getFullyQualifiedTable().getDomainObjectName();
        StringBuilder builder = new StringBuilder();
        FullyQualifiedJavaType mapperType = new FullyQualifiedJavaType(
            introspectedTable.getMyBatis3JavaMapperType());
        /*  TopLevelClass requestClass = new TopLevelClass(builder.delete(0, builder.length())
            .append(mapperType.getPackageName().replace(".mapper", "").replace("domain", "api"))
            .append(".").append(domainObjectName).append("Facade").toString());*/
        TopLevelClass requestClass = new TopLevelClass(builder.delete(0, builder.length())
            .append(mapperType.getPackageName().replace(".mapper", "").replace("domain", "service"))
            .append(".").append("impl").append(".").append(domainObjectName).append("ServiceImpl")
            .toString());
        requestClass.setVisibility(JavaVisibility.PUBLIC);
        context.getCommentGenerator().addJavaFileComment(requestClass);
        String basePage = mapperType.getPackageName();
        //添加domain的import
        requestClass.addImportedType(new FullyQualifiedJavaType(ApiExtPluginUtils.transformPackagePaths(basePage, ".request",".*")));
        requestClass.addImportedType(new FullyQualifiedJavaType(ApiExtPluginUtils.transformPackagePaths(basePage, ".dto",".*")));
        requestClass.addImportedType(new FullyQualifiedJavaType(ApiExtPluginUtils.transformPackagePaths(basePage, ".service",".*")));
        requestClass.addImportedType(new FullyQualifiedJavaType(ApiExtPluginUtils.transformPackagePaths(basePage, ".dao",".*")));
        requestClass.addImportedType(new FullyQualifiedJavaType(ApiExtPluginUtils.transformPackagePaths(basePage, ".domain",".model.*")));
        requestClass.addImportedType(new FullyQualifiedJavaType(ApiExtPluginUtils.transformPackagePaths(basePage, ".converter",".*")));

        //添加domain的import
        requestClass.addImportedType(new FullyQualifiedJavaType("com.github.pagehelper.PageInfo"));
        requestClass.addImportedType(new FullyQualifiedJavaType("lombok.RequiredArgsConstructor"));
        requestClass.addImportedType(new FullyQualifiedJavaType("lombok.extern.slf4j.Slf4j"));
        requestClass.addImportedType(new FullyQualifiedJavaType("javax.annotation.Generated"));
        requestClass.addImportedType(new FullyQualifiedJavaType("com.company.beauty.ids.support.IdsUtils"));
        requestClass.addImportedType(new FullyQualifiedJavaType("com.company.yzw.data.constants.BeautyConstants"));

        requestClass.addImportedType(
            new FullyQualifiedJavaType(("org.springframework.beans.factory.annotation.Autowired")));
        requestClass.addImportedType(
            new FullyQualifiedJavaType(("org.springframework.stereotype.Service")));
        requestClass.addImportedType(new FullyQualifiedJavaType("java.util.List"));
        requestClass.addAnnotation("@Slf4j");
        requestClass.addAnnotation("@Service");
        requestClass.addAnnotation("@RequiredArgsConstructor(onConstructor = @__(@Autowired))");
        requestClass.addSuperInterface(new FullyQualifiedJavaType(domainObjectName + "Service"));
        requestClass.addJavaDocLine("/**");
        String remarks = introspectedTable.getRemarks();
        if (StringUtility.stringHasValue(remarks)) {
            String[] remarkLines = remarks.split(System.getProperty("line.separator"));
            for (String remarkLine : remarkLines) {
                requestClass.addJavaDocLine(" * <p>" + remarkLine + "服务实现类</p>");
            }
        }

        StringBuilder sb = new StringBuilder();
        sb.append(" * @author ").append(System.getProperties().getProperty("user.name"));
        requestClass.addJavaDocLine(sb.toString());
        sb.setLength(0);
        sb.append(" * ").append("@version 1.0:")
            .append(introspectedTable.getFullyQualifiedTable().getDomainObjectName())
            .append("ServiceImpl").append(".java");
        requestClass.addJavaDocLine(sb.toString());
        sb.setLength(0);
        sb.append(" * @date ");
        sb.append(ApiExtPluginUtils.getDateString());
        requestClass.addJavaDocLine(sb.toString());
        requestClass.addJavaDocLine(" */");
        //属性
        Field daoField = new Field(StringUtils.uncapitalize(domainObjectName) + "Dao",
            new FullyQualifiedJavaType(domainObjectName + "Dao"));
        daoField.setFinal(true);
        daoField.setVisibility(JavaVisibility.PRIVATE);
        requestClass.addField(daoField);
        //
        Field convertField = new Field(StringUtils.uncapitalize(domainObjectName) + "Converter",
            new FullyQualifiedJavaType(domainObjectName + "Converter"));
        convertField.setFinal(true);
        convertField.setVisibility(JavaVisibility.PRIVATE);
        requestClass.addField(convertField);
        //增加方法
        addMethod(domainObjectName, requestClass,introspectedTable);
        updateMethod(introspectedTable, domainObjectName, requestClass);
        selectMethod(domainObjectName, requestClass);
        selectByIdsMethod(domainObjectName, requestClass);
        deleteMethod(domainObjectName, requestClass);
        enableMethod(domainObjectName, requestClass);
        selectPageMethod(domainObjectName, requestClass);
        GeneratedJavaFile generatedJavaFile = new GeneratedJavaFile(requestClass,
            context.getJavaModelGeneratorConfiguration().getTargetProject(),
            context.getProperty(PropertyRegistry.CONTEXT_JAVA_FILE_ENCODING),
            context.getJavaFormatter());

        return generatedJavaFile;
    }

    //hystrix
    public static void addMethod(String domainObjectName, TopLevelClass requestClass,IntrospectedTable introspectedTable) {
        /**
         * add方法
         *  @PostMapping("/api/{domainObjectName}/add")
         *  HttpMessageResult<Boolean> add(@RequestBody @Validated DomainAddRequest request);
         */
        IntrospectedColumn primaryColumn = introspectedTable.getPrimaryKeyColumns().stream()
                .findFirst().get();
        String columnName = StringUtils
                .capitalize(CaseUtils.toCamelCase(primaryColumn.getActualColumnName(), false, '_'));

        Method method = new Method("add");
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setReturnType(new FullyQualifiedJavaType("Boolean"));
        method.addJavaDocLine("/**");
        method.addJavaDocLine("* 新增");
        method.addJavaDocLine("* @param request 请求参数");
        method.addJavaDocLine("* @return Boolean");
        method.addJavaDocLine(" */");
        Parameter addParameter = new Parameter(
            new FullyQualifiedJavaType(domainObjectName + "AddRequest"), "request");
        method.addParameter(addParameter);
        method.addBodyLine(MessageFormat.format("{0} record = {1}Converter.convert(request);",
            domainObjectName, StringUtils.uncapitalize(domainObjectName)));
        method.addBodyLine("BeautyConstants.fillDefaultCommonRequest(record);");
        method.addBodyLine(
                MessageFormat.format("record.set{0}(IdsUtils.snowId());", columnName));
        method.addBodyLine(MessageFormat.format("{0}Dao.insert(record);",
            StringUtils.uncapitalize(domainObjectName)));
        method.addBodyLine("return  true;");
        method.addAnnotation("@Override");
        method.addAnnotation("@Generated(\"org.mybatis.generator.api.MyBatisGenerator\")");
        requestClass.addMethod(method);
    }

    public static void updateMethod(IntrospectedTable introspectedTable, String domainObjectName,
                                    TopLevelClass requestClass) {
        /**
         * update方法
         *  @PostMapping("/api/{domainObjectName}/update")
         *  HttpMessageResult<Boolean> update(@RequestBody @Validated DomainUpdateRequest request);
         */
        IntrospectedColumn primaryColumn = introspectedTable.getPrimaryKeyColumns().stream()
            .findFirst().get();
        String columnName = StringUtils
            .capitalize(CaseUtils.toCamelCase(primaryColumn.getActualColumnName(), false, '_'));
        Method method = new Method("update");
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setReturnType(new FullyQualifiedJavaType("Boolean"));
        method.addJavaDocLine("/**");
        method.addJavaDocLine("* 更新");
        method.addJavaDocLine("* @param request 请求参数");
        method.addJavaDocLine("* @return Boolean");
        method.addJavaDocLine(" */");
        Parameter updatedParameter = new Parameter(
            new FullyQualifiedJavaType(domainObjectName + "UpdateRequest"), "request");
        method.addParameter(updatedParameter);
        method.addBodyLine(MessageFormat.format("{0} record ={1}Dao.selectById(request.get{2}());",
            domainObjectName, StringUtils.uncapitalize(domainObjectName), columnName));
        method.addBodyLine(MessageFormat.format("{0}Converter.convert(request,record);",
            StringUtils.uncapitalize(domainObjectName)));
        method.addBodyLine(MessageFormat.format("{0}Dao.update(record);",
            StringUtils.uncapitalize(domainObjectName)));
        method.addBodyLine("return true;");
        method.addAnnotation("@Override");
        method.addAnnotation("@Generated(\"org.mybatis.generator.api.MyBatisGenerator\")");
        requestClass.addMethod(method);
    }

    public static void selectMethod(String domainObjectName, TopLevelClass requestClass) {
        /*
         * DomainDTO selectById(Long id);
         * */
        Method method = new Method("selectById");
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setReturnType(
            new FullyQualifiedJavaType(MessageFormat.format("{0}DTO", domainObjectName)));
        method.addJavaDocLine("/**");
        method.addJavaDocLine("* 单条记录查询");
        method.addJavaDocLine("* @param id 主键");
        method.addJavaDocLine("* @return " + MessageFormat.format("{0}DTO", domainObjectName));
        method.addJavaDocLine(" */");
        Parameter selectdParameter = new Parameter(new FullyQualifiedJavaType("Long"), "id");
        method.addParameter(selectdParameter);
        method
            .addBodyLine(MessageFormat.format("return {0}Converter.convert({1}Dao.selectById(id));",
                StringUtils.uncapitalize(domainObjectName),
                StringUtils.uncapitalize(domainObjectName)));
        method.addAnnotation("@Override");
        method.addAnnotation("@Generated(\"org.mybatis.generator.api.MyBatisGenerator\")");
        requestClass.addMethod(method);
    }

    public static void selectByIdsMethod(String domainObjectName, TopLevelClass requestClass) {
        /*
         * DomainDTO selectById(Long id);
         * */
        Method method = new Method("selectByIds");
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setReturnType(
            new FullyQualifiedJavaType(MessageFormat.format("List<{0}DTO>", domainObjectName)));
        method.addJavaDocLine("/**");
        method.addJavaDocLine("* 批量查询");
        method.addJavaDocLine("* @param ids 主键");
        method
            .addJavaDocLine("* @return " + MessageFormat.format("List<{0}DTO>", domainObjectName));
        method.addJavaDocLine(" */");
        Parameter selectdParameter = new Parameter(new FullyQualifiedJavaType("List<Long>"), "ids");
        method.addParameter(selectdParameter);
        method.addAnnotation("@Override");
        method.addAnnotation("@Generated(\"org.mybatis.generator.api.MyBatisGenerator\")");
        method.addBodyLine(
            MessageFormat.format("return {0}Converter.convert({1}Dao.selectByIds(ids));",
                StringUtils.uncapitalize(domainObjectName),
                StringUtils.uncapitalize(domainObjectName)));
        requestClass.addMethod(method);
    }

    public static void deleteMethod(String domainObjectName, TopLevelClass requestClass) {
        /**
         * deleteById
         */
        Method method = new Method("deleteById");
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setReturnType(new FullyQualifiedJavaType("Boolean"));
        method.addJavaDocLine("/**");
        method.addJavaDocLine("* 单条记录删除");
        method.addJavaDocLine("* @param id 主键");
        method.addJavaDocLine("* @return  Boolean");
        method.addJavaDocLine(" */");
        Parameter deleteParameter = new Parameter(new FullyQualifiedJavaType("Long"), "id");
        method.addParameter(deleteParameter);
        method.addBodyLine(MessageFormat.format("{0}Dao.deleteById(id);",
            StringUtils.uncapitalize(domainObjectName)));
        method.addBodyLine("return true;");
        method.addAnnotation("@Override");
        method.addAnnotation("@Generated(\"org.mybatis.generator.api.MyBatisGenerator\")");
        requestClass.addMethod(method);
    }

    public static void enableMethod(String domainObjectName, TopLevelClass requestClass) {
        /**
         * setEnable 启用/禁用
         */
        Method method = new Method("setEnable");
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setReturnType(new FullyQualifiedJavaType("Boolean"));
        method.addJavaDocLine("/**");
        method.addJavaDocLine("* 启用/禁用");
        method.addJavaDocLine("* @param id 主键");
        method.addJavaDocLine("* @param isEnable 启用/禁用");
        method.addJavaDocLine("* @return  Boolean");
        method.addJavaDocLine(" */");
        Parameter enableIdParameter = new Parameter(new FullyQualifiedJavaType("Long"), "id");
        Parameter enableParameter = new Parameter(new FullyQualifiedJavaType("Integer"),
            "isEnable");
        method.addParameter(enableIdParameter);
        method.addParameter(enableParameter);
        method.addBodyLine(MessageFormat.format("{0} record ={1}Dao.selectById(id);",
            domainObjectName, StringUtils.uncapitalize(domainObjectName)));
        method.addBodyLine("record.setIsEnable(isEnable);");
        method.addBodyLine(MessageFormat.format("{0}Dao.update(record);",
            StringUtils.uncapitalize(domainObjectName)));
        method.addBodyLine("return true;");
        method.addAnnotation("@Override");
        method.addAnnotation("@Generated(\"org.mybatis.generator.api.MyBatisGenerator\")");
        requestClass.addMethod(method);
    }

    public static void selectPageMethod(String domainObjectName, TopLevelClass requestClass) {
        Method method = new Method("selectPage");
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setReturnType(
            new FullyQualifiedJavaType(MessageFormat.format("{0}DTO", domainObjectName)));
        method.addJavaDocLine("/**");
        method.addJavaDocLine("* 分页查询");
        method.addJavaDocLine("* @param request 请求参数");
        method.addJavaDocLine(
            "* @return " + MessageFormat.format("PageInfo<{0}DTO>", domainObjectName));
        method.setReturnType(
            new FullyQualifiedJavaType(MessageFormat.format("PageInfo<{0}DTO>", domainObjectName)));
        method.addJavaDocLine(" */");
        Parameter addParameter = new Parameter(
            new FullyQualifiedJavaType(domainObjectName + "SelectPageRequest"), "request");
        method.addParameter(addParameter);
        method.addBodyLine(MessageFormat.format("return {0}Converter.convertPage({1}Dao.selectPage(request));",
                        StringUtils.uncapitalize(domainObjectName),
                        StringUtils.uncapitalize(domainObjectName)));
        method.addAnnotation("@Override");
        method.addAnnotation("@Generated(\"org.mybatis.generator.api.MyBatisGenerator\")");
        requestClass.addMethod(method);
    }
}